package com.fhzn.auth.tools;


import com.fhzn.commons.toolkit.exception.BuzException;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 * AES对称加密
 *
 * @author fhzn
 */
public class AESEncryptorUtils {

    /**
     * 算法名称
     */
    private static final String KEY_ALGORITHM = "AES";

    /**
     * 算法名称/加密模式/填充方式
     */
    private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";

    /**
     * 密钥
     */
    public static final String KEY_FOR_AES = "7@iJ";

    public static final int SALT_SIZE = 16;

    /**
     * 生成随机密钥，安全性较高，但密钥需要保存
     *
     * @param key 密钥
     * @return 密钥
     * @throws NoSuchAlgorithmException 异常
     */
    @Deprecated
    public static Key toRandomKey(String key) throws NoSuchAlgorithmException {
        // 返回生成指定算法的秘密密钥的 KeyGenerator对象
        KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
        // 初始化此密钥生成器，使其具有确定的密钥大小（AES 要求密钥长度为 128）
        kgen.init(128, new SecureRandom(key.getBytes(StandardCharsets.UTF_8)));
        // 生成一个密钥
        SecretKey secretKey = kgen.generateKey();
        // 构造密钥
        byte[] enCodeFormat = secretKey.getEncoded();
        return new SecretKeySpec(enCodeFormat, KEY_ALGORITHM);
    }

    /**
     * 生成一个固定密钥
     *
     * @param password 长度必须是16的倍数
     * @return 密钥
     */
    private static Key toKey(String password) {
        return new SecretKeySpec(password.getBytes(StandardCharsets.UTF_8), KEY_ALGORITHM);
    }

    /**
     * 将二进制转换成十六进制
     *
     * @param buf 二进制数组
     * @return 十六进制
     */
    private static String parseByte2HexStr(byte[] buf) {
        StringBuilder sb = new StringBuilder();
        for (byte b : buf) {
            String hex = Integer.toHexString(b & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 将十六进制转换为二进制
     *
     * @param hexStr 下一个十六进制字符串
     * @return 二进制数组
     */
    private static byte[] parseHexStr2Byte(String hexStr) {
        int number = 2;
        if (hexStr.isEmpty()) {
            return null;
        }
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / number; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

    /**
     * 加密
     *
     * @param password 密码
     * @param salt     盐
     */
    public static String encrypt(String password, String salt) {
        if (StringUtils.isBlank(password)) {
            return StringUtils.EMPTY;
        }
        try {
            // 生成密钥
            Key key = toKey(salt);
            // 将String转换为二进制
            byte[] byteContent = password.getBytes(StandardCharsets.UTF_8);
            // 创建密码器
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
            // 初始化为加密模式
            cipher.init(Cipher.ENCRYPT_MODE, key);
            // 执行加密加密
            byte[] result = cipher.doFinal(byteContent);
            return parseByte2HexStr(result);
        } catch (Exception e) {
            throw new BuzException("加密失败");
        }
    }

    /**
     * 解密
     *
     * @param content  密文
     * @param password 密码
     */
    public static String decrypt(String content, String password) {
        if (StringUtils.isBlank(content)) {
            return "";
        }

        try {
            // 将十六进制转换为二进制
            byte[] contentHex = parseHexStr2Byte(content);

            // 生成密钥
            Key key = toKey(password);
            // 创建密码器
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
            // 初始化解码模式
            cipher.init(Cipher.DECRYPT_MODE, key);
            // 解密
            byte[] result = new byte[0];
            if (contentHex != null) {
                result = cipher.doFinal(contentHex);
            }

            return new String(result, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
}
